#include "Triangle.h"


Triangle::Triangle(vec4 _pos, vec3 _rot, vec3 _pt1, vec3 _pt2, vec3 _pt3) :Shape(_pos, _rot){
	verts[0] = _pt1;
	verts[1] = _pt2;
	verts[2] = _pt3;
	theNorm = normalize(cross(_pt2 - _pt1, _pt3 - _pt1));	//calculate the surface normal

	theCenter = (_pt1 + _pt2 + _pt3) / 3.0f;				//calculate the geometric center
	//printf("Triangle normal: (%f, %f, %f)\n", theNorm.x, theNorm.y, theNorm.z);
	//edgeNorms[0] = normalize(cross(_pt3 - _pt2, theNorm));
	//edgeNorms[1] = normalize(cross(_pt1 - _pt3, theNorm));
	//edgeNorms[2] = normalize(cross(_pt2 - _pt1, theNorm));
}


Triangle::~Triangle(){
}

bool Triangle::intersect(Intersection &_int){
	Stats::instance()->primTest();	//increment the intersection test count
	float epsilon = 0.000001f;
	//printf("Triangle\n");
	//ray-triangle intersection test
	Ray _theRay = *(_int.ray());
	vec3 triPos = pos.xyz();
	vec3 rayOrigin = _theRay.origin();
	vec3 rayDirection = _theRay.direction();
	rayOrigin -= triPos;
	vec3 e1, e2;
	vec3 P, Q, T;
	float det, inv_det, u, v;
	float _dist;
	//Find vectors for two edges sharing V1
	e1 = verts[1] - verts[0];
	e2 = verts[2] - verts[0];
	//Begin calculation determinant - also used to calculate u parameter
	P = cross(rayDirection, e2);
	//if the determinant is near zero, the ray lies in the plane of the triangle
	det = dot(e1, P);
	if (det > -epsilon && det < epsilon)
		return false;
	inv_det = 1.0f / det;

	//calculate distance from verts[0] to ray origin
	T = rayOrigin - verts[0];
	//calculate u parameter and test bound
	u = dot(T, P) * inv_det;
	//the intersection lies outside of the triangle
	if (u < 0.0f || u > 1.0f)
		return false;
	//prepare to test v parameter
	Q = cross(T, e1);
	//Calculate V parameter and test bound
	v = dot(rayDirection, Q) * inv_det;
	//The intersection lies outside of the triangle
	if (v < 0.0f || u + v > 1.0f)
		return false;
	_dist = dot(e2, Q) * inv_det;

	//if it's too close
	if (_dist < _theRay.minDist())
		return false;


	//if it got here, it's definitely inside the triangle
	if (_dist < _int.dist()){
		_int.dist(_dist);
		_int.shape(this);
		_int.surfNorm(theNorm);

	}
	_int.intersected(true);
	Stats::instance()->primInt();	//increment the intersection count
	return true;
}

vec4 Triangle::getColor(Intersection &_int){
	//calculate the surface color based on the Triangle's ShaderCollection
	if (shade == NULL){
		return vec4(0, 0.3, 0.4, 1);

	}
	return shade->getColor(_int);
}

vec3 Triangle::getMaxBound(){
	float maxX = max(max(verts[0].x, verts[1].x), max(verts[0].x, verts[2].x));
	float maxY = max(max(verts[0].y, verts[1].y), max(verts[0].y, verts[2].y));
	float maxZ = max(max(verts[0].z, verts[1].z), max(verts[0].z, verts[2].z));
	return vec3(maxX, maxY, maxZ);
}
vec3 Triangle::getMinBound(){
	float minX = min(min(verts[0].x, verts[1].x), min(verts[0].x, verts[2].x));
	float minY = min(min(verts[0].y, verts[1].y), min(verts[0].y, verts[2].y));
	float minZ = min(min(verts[0].z, verts[1].z), min(verts[0].z, verts[2].z));
	return vec3(minX, minY, minZ);
}

vec3 Triangle::getCenter(){
	return theCenter;
}

